/*
 * Alloy Analyzer
 * Copyright (c) 2002 Massachusetts Institute of Technology
 *
 * The Alloy Analyzer is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * The Alloy Analyzer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the Alloy Analyzer; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package alloy.ast;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * Alloy Analyzer
 * Copyright (c) 2001
 * Massachusetts Institute of Technology
 *
 * Class: InvocationFormula
 * owner: brianlin / msridhar
 * Interface status: unstable
 * Implementation status: unstable
 *
 * AST node representing a/an InvocationFormula
 */


public class InvocationFormula extends AbstractFormula implements Formula, Invocation {

    /**
     * index of function name in child list
     */
    private static final int RECEIVER_INDEX = 0;

    /**
     * index of predicate/function name in child list
     */
    private static final int INVOCABLE_INDEX = 1;

    /**
     * index of exprs in child list
     */
    private static final int EXPRS_INDEX = 2;

    /**
     * the mapping between the var types of the invoked function and the argument
     * types of this
     */
    private Map _varTypeToParamType;

    private InvocablePara _invocable;

    public InvocationFormula(Location location_, Expr receiver_, QualifiedName invocableName_, Exprs exprs_) {
        super(location_, receiver_, invocableName_, exprs_);
    }


    public InvocationFormula(Expr receiver_, QualifiedName invocableName_, Exprs exprs_) {
        this(Location.UNKNOWN, receiver_, invocableName_, exprs_);
    }

    //GET AND SET METHODS

    public List getArgs() {
        List args = new ArrayList();
        Expr receiver = getReceiver();
        if (!(receiver instanceof EmptyExpr)) {
            args.add(receiver);
        }
        Iterator exprIter = getExprs().getExprIter();
        while (exprIter.hasNext()) {
            args.add(exprIter.next());
        }
        return args;
    }

    /**
     * gets the receiver name of this
     * @return the {@link Expr}
     */
    public Expr getReceiver() {
        return (Expr)childAt(RECEIVER_INDEX);
    }

    /** set the Receiver of this */
    public void setReceiver(Expr newChild_) {
        setChild(RECEIVER_INDEX, newChild_);
    }


    /**
     * gets the function name of this
     * @return the {@link QualifiedName}
     */
    public QualifiedName getInvocableName() {
        return (QualifiedName)childAt(INVOCABLE_INDEX);
    }

    /** set the Function of this */
    public void setInvocableName(QualifiedName newChild_) {
        setChild(INVOCABLE_INDEX, newChild_);
    }

    /**
     * gets the exprs of this
     * @return the {@link Exprs}
     */
    public Exprs getExprs() {
        return (Exprs)childAt(EXPRS_INDEX);
    }

    /** set the Exprs of this */
    public void setExprs(Exprs newChild_) {
        setChild(EXPRS_INDEX, newChild_);
    }

    /**
     * get the var type mapping of this, the bindings
     * between the invoked function's var types and the
     * actual types passed in by this
     * @return the var type mapping
     */
    public Map getVarTypeMapping() {
        return _varTypeToParamType;
    }

    /**
     * set the var type mapping of this, the bindings
     * between the invoked function's var types and the
     * actual types passed in by this
     * @param varTypeMapping_ the new var type mapping
     */
    public void setVarTypeMapping(Map varTypeMapping_) {
        _varTypeToParamType = varTypeMapping_;
    }

    public InvocablePara getInvocable() {
        return _invocable;
    }

    public void setInvocable(InvocablePara invocable_) {
        _invocable = invocable_;
    }

    /**
     * accept an AST visitor
     * @param visitor_ the visitor
     */
    protected void acceptVisitor(ASTVisitor visitor_) {
        visitor_.visit(this);
    }

    /**
     * accept a returning AST visitor
     * @param visitor_ the visitor
     * @return the Object returned by the visitor
     */
    protected Object acceptReturnVisitor(ASTReturnVisitor visitor_) {
        return visitor_.visit(this);
    }

    public String nodeString() {
        StringBuffer ret = new StringBuffer();
        if (!(getReceiver() instanceof EmptyExpr)) {
            ret.append(getReceiver().nodeString() + "..");
        }
        ret.append(getInvocableName().nodeString() + "( " +
                   getExprs().childrenStr("", ", ", "") + " )");
        return ret.toString();
    }

    public String toString()
    {
        return nodeString();
    }
}
